#include "Serial.h"

Serial::Serial(const char *portName, DWORD dwBaudRate, Logger *pLogger) {

    m_pLogger = pLogger;        //Setup the logger
    this->connected = false;    //We're not yet connected

    int portNameLength = MultiByteToWideChar( CP_UTF8, 0, portName, -1, NULL, 0 );          //Get the length of the string
    wchar_t *pwPortName = new wchar_t[ portNameLength ];                                    //Define new wide char with the correct length
    MultiByteToWideChar( CP_UTF8, 0, portName, -1, (LPWSTR)pwPortName, portNameLength );    //convert char* to wide char

    //Try to connect to the given port through CreateFile
    this->hSerial = CreateFile( pwPortName,
            GENERIC_READ | GENERIC_WRITE,
            0,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL );

    if( this->hSerial == INVALID_HANDLE_VALUE ) { //Check if the connection was successful
        if( GetLastError() == ERROR_FILE_NOT_FOUND )    //If not success full display an Error
            m_pLogger->log( QString( "ERROR: Handle was not attached. Reason: %1 not available." ).arg( portName ) );
        else
            m_pLogger->log( QString( "ERROR!!!" ) );
    } else {
        DCB dcbSerialParams = {0};  //If connected we try to set the comm parameters

        if ( !GetCommState( this->hSerial, &dcbSerialParams ) ) { //Try to get the current
            pLogger->log( QString( "failed to get current serial parameters!" ) );  //If impossible, show an error
        } else {
            //Define serial connection parameters for the arduino board
            dcbSerialParams.BaudRate = dwBaudRate; //9600;
            dcbSerialParams.ByteSize = 8;
            dcbSerialParams.StopBits = ONESTOPBIT;
            dcbSerialParams.Parity = NOPARITY;

             //Set the parameters and check for their proper application
             if( !SetCommState( hSerial, &dcbSerialParams ) ) {
                m_pLogger->log( QString( "ALERT: Could not set Serial Port parameters" ) );
             } else {
                 this->connected = true;      //If everything went fine we're connected
                 Sleep( ARDUINO_WAIT_TIME );  //We wait 2s as the arduino board will be reseting
             }
        }
    }
}

Serial::~Serial() {
    //Check if we are connected before trying to disconnect
    if( this->connected ) {
        this->connected = false;        //We're no longer connected
        CloseHandle( this->hSerial );   //Close the serial handler
    }
}

int Serial::ReadData( char *buffer, unsigned int nbChar ) {

    DWORD bytesRead;        //Number of bytes we'll have read
    unsigned int toRead;    //Number of bytes we'll really ask to read

    //Use the ClearCommError function to get status info on the Serial port
    ClearCommError( this->hSerial, &this->errors, &this->status );

    //Check if there is something to read
    if( this->status.cbInQue > 0 ) {
        //If there is we check if there is enough data to read the required number
        //of characters, if not we'll read only the available characters to prevent
        //locking of the application.
        if( this->status.cbInQue > nbChar )
            toRead = nbChar;
        else
            toRead = this->status.cbInQue;

        //Try to read the require number of chars, and return the number of read bytes on success
        if( ReadFile( this->hSerial, buffer, toRead, &bytesRead, NULL ) && bytesRead != 0 )
            return bytesRead;
    }
    return -1;  //If nothing has been read, or that an error was detected return -1
}

bool Serial::WriteData( const char *buffer, unsigned int nbChar ) {
    m_pLogger->log( QString( "Sending Tweet to the Arduino..." ) );
    DWORD bytesSend;

    //Try to write the buffer on the Serial port
    if(!WriteFile( this->hSerial, ( void* )buffer, nbChar, &bytesSend, 0 ) ) {
        ClearCommError( this->hSerial, &this->errors, &this->status ); //In case it don't work get comm error and return false
        m_pLogger->log( QString( "Error Writing to the Serial Port" ) );
        return false;
    }
    return true;
}

bool Serial::IsConnected() {
    return this->connected; //Simply return the connection status
}
